#include "sh8601z.h"

/*
 *  注意事项：
 *  该屏幕的TE信号和屏幕本身的刷新速度有关，就算我们不发数据给屏幕它自己也会周期性刷新，因此很鸡肋
 *  ESP32S3的QSPI为半双工通信，只能发不能收
 */

static spi_device_handle_t spi_device_handle = NULL;

typedef enum
{
    NOP = 0x00,
    SWRESET = 0x01,
    RD_DIDIF = 0x04,
    RD_NUMED = 0x05,
    RD_DPM = 0x0a,
    RD_DMADCTL = 0x0b,
    RD_DCOLMOD = 0x0c,
    RD_DIM = 0x0d,
    RD_DSM = 0x0e,
    RD_DSDR = 0x0f,
    SLP_IN = 0x10,
    SLP_OUT = 0x11,
    PTL_ON = 0x12,
    NOR_ON = 0x13,
    INV_OFF = 0x20,
    INV_ON = 0x21,
    ALLP_OFF = 0x22,
    ALLP_ON = 0x23,
    DISP_OFF = 0x28,
    DISP_ON = 0x29,
    CASET = 0x2a,
    PASER = 0x2b,
    RAMWR = 0x2c,
    PTLAR = 0x30,
    PTLAC = 0x31,
    TE_OFF = 0x34,
    TE_ON = 0x35,
    MADCTL = 0x36,
    IDMOFF = 0x38,
    IDMON = 0x39,
    COLMOD = 0x3a,
    RAMWRC = 0x3c,
    WR_TESCAN = 0x44,
    RD_TESCAN = 0x45,
    SPI_RD_OFF = 0x46,
    SPI_RD_ON = 0x47,
    AOD_OFF = 0x48,
    AOD_ON = 0x49,
    AOD_WR_DISBV = 0x4a,
    AOD_RD_DISBV = 0x4b,
    DSTB = 0x4f,
    WR_DISBV = 0x51,
    RD_DISBV = 0x52,
    WR_CTRLD1 = 0x53,
    RD_CTRLD1 = 0x54,
    WR_CTRLD2 = 0x55,
    RD_CTRLD2 = 0x56,
    WR_CE = 0x58,
    RD_CE = 0x59,
    HBM_WR_DISBV = 0x63,
    HBM_RD_DISBV = 0x64,
    HBM_CTRL = 0x66,
    COLOPT = 0x80,
    RD_DDBS = 0xa1,
    RD_DDBC = 0xa8,
    RD_FCS = 0xaa,
    RD_CCS = 0xaf,
    SPI_MODE = 0xc4,
    RD_ID1 = 0xda,
    RD_ID2 = 0xdb,
    RD_ID3 = 0xdc,
}SH8601Z_Reg_TypeDef;

void post_callback(spi_transaction_t *tran)
{
    int temp = (int )tran->user;

    if(temp == 101)
    {

        /*
        *  在这个地方 设置LVGL flush ready
        */
        lv_disp_flush_ready(lv_disp_drv);
    }
}

void sh8601z_set_bl(uint8_t level)
{

}

void sh8601z_set_rs(uint8_t level)
{
    gpio_set_level(SH8601Z_RS_PIN, level);
}

void sh8601z_set_dc(uint8_t level)
{
    gpio_set_level(SH8601Z_DC_PIN, level);
}

void sh8601z_set_cs(uint8_t level)
{
    gpio_set_level(SH8601Z_MNSS_PIN, level);
}

uint8_t sh8601z_get_te(void)
{
    return 0;
}

/*
 *  @breif      SH8601Z延时一段时间
 *  @note       该函数需要自己移植
 *  @param      time：延时时间，单位ms
 *  @retval     无
 */
void sh8601z_delay(uint32_t time)
{
    vTaskDelay(pdMS_TO_TICKS((time)));
}

/*
 *  @breif      SH8601Z硬件配置
 *  @note       QSPI配置，需要自己移植
 *  @param      无
 *  @retval     无
 */
void sh8601z_config(void)
{
    spi_bus_config_t spi_bus_conf = {
            .data0_io_num = SH8601Z_QSPI_DAT0,
            .data1_io_num = SH8601Z_QSPI_DAT1,
            .data2_io_num = SH8601Z_QSPI_DAT2,
            .data3_io_num = SH8601Z_QSPI_DAT3,
            .sclk_io_num = SH8601Z_QSPI_SCK,
            .max_transfer_sz = SH8601Z_SEND_MAX_SIZE,
            .flags = SPICOMMON_BUSFLAG_MASTER | SPICOMMON_BUSFLAG_GPIO_PINS,
    };

    ESP_ERROR_CHECK(spi_bus_initialize(SPI2_HOST,&spi_bus_conf,SPI_DMA_CH_AUTO));

    spi_device_interface_config_t spi_device_interface_conf = {
            .command_bits = 8,
            .address_bits = 24,
            .dummy_bits = 0,
            .mode = 0,
            .clock_speed_hz = SPI_MASTER_FREQ_80M,
            .spics_io_num = SH8601Z_QSPI_NSS,
            .queue_size = SH8601Z_SEND_QUEUES,
            .flags = SPI_DEVICE_HALFDUPLEX,
            .post_cb = post_callback,
    };

    ESP_ERROR_CHECK(spi_bus_add_device(SPI2_HOST,&spi_device_interface_conf,&spi_device_handle));

    gpio_config_t gpio_conf = {
            .pin_bit_mask = (1ull << SH8601Z_RS_PIN) | (1ull << SH8601Z_PWR_PIN),
            .mode = GPIO_MODE_OUTPUT,
            .pull_up_en = GPIO_PULLUP_ENABLE,
            .pull_down_en = GPIO_PULLDOWN_DISABLE,
            .intr_type = GPIO_INTR_DISABLE,
    };

    ESP_ERROR_CHECK(gpio_config(&gpio_conf));

    ESP_ERROR_CHECK(gpio_set_level(SH8601Z_RS_PIN,1));
    ESP_ERROR_CHECK(gpio_set_level(SH8601Z_PWR_PIN,0));
    vTaskDelay(pdMS_TO_TICKS(10));
    ESP_ERROR_CHECK(gpio_set_level(SH8601Z_PWR_PIN,1));
    vTaskDelay(pdMS_TO_TICKS(10));
    ESP_ERROR_CHECK(gpio_set_level(SH8601Z_RS_PIN,0));
    vTaskDelay(pdMS_TO_TICKS(10));
    ESP_ERROR_CHECK(gpio_set_level(SH8601Z_RS_PIN,1));
    vTaskDelay(pdMS_TO_TICKS(10));
}

/*
 *  @breif      SH8601Z QSPI 1线发送 仅仅使用到DAT0
 *  @note       flag中的SPI_TRANS_MULTILINE_CMD和SPI_TRANS_MULTILINE_ADDR意思是命令和地址发送格式和发送数据一样
 *  @param      command：寄存器，左移八位形成地址
 *              buf:数据
 *              buf_len:数据长度
 *  @retval     无
 */
void qspi_1l_write_command_and_data(uint8_t command, const uint8_t *buf, uint16_t buf_len)
{
    spi_transaction_t tran;
    memset(&tran,0, sizeof(spi_transaction_t));
    tran.cmd = 0x02;
    tran.addr = (((uint32_t)command) << 8);
    if(buf_len == 0)
        tran.tx_buffer = NULL;
    else
        tran.tx_buffer = buf;
    tran.length = 8 * buf_len;
    tran.flags = (SPI_TRANS_MULTILINE_CMD | SPI_TRANS_MULTILINE_ADDR);
    ESP_ERROR_CHECK(spi_device_polling_transmit(spi_device_handle,&tran));
}

/*
 *  @breif      SH8601Z QSPI 4线发送
 *  @note       flag中的 SPI_TRANS_MODE_QIO 和 SPI_TRANS_MULTILINE_ADDR
 *              意思是发送地址和发送数据的时候一样味QSPI 4线发送，而命令0x12为QSPI 1线
 *  @param      command：寄存器，左移八位形成地址
 *              buf:数据
 *              buf_len:数据长度
 *  @retval     无
 */
void qspi_4l_write_command_and_data(uint8_t command,const uint8_t *buf,uint16_t buf_len)
{
    spi_transaction_ext_t tran;
    memset(&tran,0, sizeof(spi_transaction_ext_t));
    tran.command_bits = 8;
    tran.address_bits = 24;
    tran.dummy_bits = 0;
    tran.base.cmd = 0x12;
    tran.base.addr = (((uint32_t)command) << 8);
    tran.base.length = 8 * buf_len;
    tran.base.tx_buffer = buf;
    tran.base.flags = (SPI_TRANS_MODE_QIO | SPI_TRANS_MULTILINE_ADDR);
    ESP_ERROR_CHECK(spi_device_polling_transmit(spi_device_handle,&tran.base));
}

/*
 *  @breif      SH8601Z初始化
 *  @note       检验初始化是否成功可以先使用0x23命令（全点打开），然后再修改0x51命令的数据(修改亮度)
 *              注意：这个屏幕是AMOLED屏幕，初始化完成不会有任何显示，必须要先刷一次屏才会有数据
 *  @param      无
 *  @retval     无
 */
void SH8601Z_Init(void)
{
    sh8601z_config();

    SH8601Z_Sleep_Out();
    sh8601z_delay(80);
    SH8601Z_Control_Interface_Pixel_Format(0x55);
    SH8601Z_Write_CTRL_Display_1(0x20);
    SH8601Z_Write_Display_Brightness_Value(0xff);
    SH8601Z_Display_On();
}

/*
 *  @breif      SH8601Z空操作
 *  @note       无
 *  @param      无
 *  @retval     无
 */
void SH8601Z_No_Operation(void)
{
    qspi_1l_write_command_and_data(NOP, NULL, 0);
}

/*
 *  @breif      SH8601Z软件复位
 *  @note       无
 *  @param      无
 *  @retval     无
 */
void SH8601Z_Software_Reset(void)
{
    qspi_1l_write_command_and_data(SWRESET, NULL, 0);
}

/*
 *  @breif      SH8601Z读身份信息
 *  @note       未实现
 *  @param      无
 *  @retval
 */
uint32_t SH8601Z_Read_Display_Identification_Information(void)
{
    return 0xffffffff;
}

/*
 *  @breif      SH8601Z读DSI错误数
 *  @note       未实现
 *  @param      无
 *  @retval
 */
uint8_t SH8601Z_Read_Number_of_the_Errors_on_DSI(void)
{
    return 0xff;
}

/*
 *  @breif      SH8601Z读电源模式
 *  @note       未实现
 *  @param      无
 *  @retval
 */
uint8_t SH8601Z_Read_Display_Power_Mode(void)
{
    return 0xff;
}

/*
 *  @breif      SH8601Z读MADCTL
 *  @note       未实现
 *  @param      无
 *  @retval
 */
uint8_t SH8601Z_Read_Display_MADCTL(void)
{
    return 0xff;
}

/*
 *  @breif      SH8601Z读像素格式
 *  @note       未实现
 *  @param      无
 *  @retval
 */
uint8_t SH8601Z_Read_Display_Pixel_Format(void)
{
    return 0xff;
}

/*
 *  @breif      SH8601Z读图像格式
 *  @note       未实现
 *  @param      无
 *  @retval
 */
uint8_t SH8601Z_Read_Display_Image_Mode(void)
{
    return 0xff;
}

/*
 *  @breif      SH8601Z读信号模式
 *  @note       未实现
 *  @param      无
 *  @retval
 */
uint8_t SH8601Z_Read_Display_Signal_Mode(void)
{
    return 0xff;
}

/*
 *  @breif      SH8601Z读自我测试结果
 *  @note       未实现
 *  @param      无
 *  @retval
 */
uint8_t SH8601Z_Read_Display_Self_Diagnostic_Result(void)
{
    return 0xff;
}

/*
 *  @breif      SH8601Z进入睡眠模式
 *  @note       无
 *  @param      无
 *  @retval     无
 */
void SH8601Z_Sleep_In(void)
{
    qspi_1l_write_command_and_data(SLP_IN, NULL, 0);
}

/*
 *  @breif      SH8601Z退出睡眠模式
 *  @note       无
 *  @param      无
 *  @retval     无
 */
void SH8601Z_Sleep_Out(void)
{
    qspi_1l_write_command_and_data(SLP_OUT, NULL, 0);
}

/*
 *  @breif      SH8601Z打开部分显示模式
 *  @note       无
 *  @param      无
 *  @retval     无
 */
void SH8601Z_Partial_Display_Mode_On(void)
{
    qspi_1l_write_command_and_data(PTL_ON, NULL, 0);
}

/*
 *  @breif      SH8601Z打开正常显示模式
 *  @note       无
 *  @param      无
 *  @retval     无
 */
void SH8601Z_Normal_Display_Mode_On(void)
{
    qspi_1l_write_command_and_data(NOR_ON, NULL, 0);
}

/*
 *  @breif      SH8601Z关闭反转显示模式
 *  @note       无
 *  @param      无
 *  @retval     无
 */
void SH8601Z_Display_Inversion_Off(void)
{
    qspi_1l_write_command_and_data(INV_OFF, NULL, 0);
}

/*
 *  @breif      SH8601Z打开反转显示模式
 *  @note       无
 *  @param      无
 *  @retval     无
 */
void SH8601Z_Display_Inversion_On(void)
{
    qspi_1l_write_command_and_data(INV_ON, NULL, 0);
}

/*
 *  @breif      SH8601Z关闭所有点显示
 *  @note       无
 *  @param      无
 *  @retval     无
 */
void SH8601Z_All_Pixel_Off(void)
{
    qspi_1l_write_command_and_data(ALLP_OFF, NULL, 0);
}

/*
 *  @breif      SH8601Z打开所有点显示
 *  @note       无
 *  @param      无
 *  @retval     无
 */
void SH8601Z_All_Pixel_On(void)
{
    qspi_1l_write_command_and_data(ALLP_ON, NULL, 0);
}

/*
 *  @breif      SH8601Z关闭显示
 *  @note       无
 *  @param      无
 *  @retval     无
 */
void SH8601Z_Display_Off(void)
{
    qspi_1l_write_command_and_data(DISP_OFF, NULL, 0);
}

/*
 *  @breif      SH8601Z打开显示
 *  @note       无
 *  @param      无
 *  @retval     无
 */
void SH8601Z_Display_On(void)
{
    qspi_1l_write_command_and_data(DISP_ON, NULL, 0);
}

/*
 *  @breif      SH8601Z设置起始列和结束列
 *  @note       无
 *  @param      sc：起始列
 *              ec：结束列
 *  @retval     无
 */
void SH8601Z_Column_Address_Set(uint16_t sc,uint16_t ec)
{
    uint8_t buf[4] = {0};
    buf[0] = BYTE1(sc);
    buf[1] = BYTE0(sc);
    buf[2] = BYTE1(ec);
    buf[3] = BYTE0(ec);
    qspi_1l_write_command_and_data(CASET, buf, 4);
}

/*
 *  @breif      SH8601Z设置起始行和结束行
 *  @note       无
 *  @param      sp：起始列
 *              ep：结束列
 *  @retval     无
 */
void SH8601Z_Page_Address_Set(uint16_t sp, uint16_t ep)
{
    uint8_t buf[4] = {0};
    buf[0] = BYTE1(sp);
    buf[1] = BYTE0(sp);
    buf[2] = BYTE1(ep);
    buf[3] = BYTE0(ep);
    qspi_1l_write_command_and_data(PASER, buf, 4);
}

/*
 *  @breif      SH8601Z从设定的起始列和起始行开始发送数据
 *  @note
 *  @param      buf：数据
 *              buf_len：数据长度
 *  @retval     无
 */
void SH8601Z_Memory_Write_Start(uint8_t *buf,uint16_t buf_len)
{
    //发数据的时候一定要用上QSPI
    qspi_4l_write_command_and_data(RAMWR,buf,buf_len);
}

/*
 *  @breif      SH8601Z设置部分显示模式的起始列和结束列
 *  @note       仅在部分显示模式下有效
 *  @param      psp：部分显示模式的起始列
 *              pep：部分显示模式的结束列
 *  @retval     无
 */
void SH8601Z_Partial_Area_Row_Set(uint16_t psp, uint16_t pep)
{
    uint8_t buf[4] = {0};
    buf[0] = BYTE1(psp);
    buf[1] = BYTE0(psp);
    buf[2] = BYTE1(pep);
    buf[3] = BYTE0(pep);
    qspi_1l_write_command_and_data(PTLAR, buf, 4);
}

/*
 *  @breif      SH8601Z设置部分显示模式的起始行和结束行
 *  @note       仅在部分显示模式下有效
 *  @param      psp：部分显示模式的起始行
 *              pep：部分显示模式的结束行
 *  @retval     无
 */
void SH8601Z_Partial_Area_Column_Set(uint16_t psc,uint16_t pec)
{
    uint8_t buf[4] = {0};
    buf[0] = BYTE1(psc);
    buf[1] = BYTE0(psc);
    buf[2] = BYTE1(pec);
    buf[3] = BYTE0(pec);
    qspi_1l_write_command_and_data(PTLAC, buf, 4);
}

/*
 *  @breif      SH8601Z关闭撕裂效应
 *  @note       无
 *  @param      无
 *  @retval     无
 */
void SH8601Z_Tearing_Effect_Off(void)
{
    qspi_1l_write_command_and_data(TE_OFF, NULL, 0);
}

/*
 *  @breif      SH8601Z打开撕裂效应
 *  @note       这个应该是能显示出一行一帧的那种
 *  @param      tem
 *              0：只有H信息，不包含V信息
 *              1：包括H和V信息
 *  @retval     无
 */
void SH8601Z_Tearing_Effect_On(uint8_t tem)
{
    uint8_t buf[1] = {0};
    buf[0] = tem & 0x01;
    qspi_1l_write_command_and_data(TE_ON, buf, 1);
}

/*
 *  @breif      SH8601Z设置内存扫描模式
 *  @note
 *  @param      byte[6]：内存写方向水平翻转
 *              0：内存写入正向
 *              1：内存写入反向
 *              byte[3]：颜色顺序
 *              0：RGB
 *              1：BGR
 *  @retval
 */
void SH8601Z_Memory_Data_Access_Control(uint8_t byte)
{
    uint8_t buf[1] = {0};
    buf[0] = byte & 0x48;
    qspi_1l_write_command_and_data(MADCTL, buf, 1);
}

/*
 *  @breif      SH8601Z关闭空闲模式
 *  @note       无
 *  @param      无
 *  @retval     无
 */
void SH8601Z_Idle_Mode_Off(void)
{
    qspi_1l_write_command_and_data(IDMOFF, NULL, 0);
}

/*
 *  @breif      SH8601Z打开空闲模式
 *  @note       无
 *  @param      无
 *  @retval     无
 */
void SH8601Z_Idle_Mode_On(void)
{
    qspi_1l_write_command_and_data(IDMON, NULL, 0);
}

/*
 *  @breif      SH8601Z设置像素格式
 *  @note
 *  @param      byte[7]->SPI_PF_SEL：SPI像素格式选择。
 *              0：IFPF[2:0] is used by the SPI interface.
 *              1：VIPF[2:0] is used by the SPI interface.
 *              byte[6:4]->VIPF：This command is used by SPI_PF_SEL=1.
 *              0：Disable
 *              1:8-bit / pixel 256 Gray
 *              2:8-bit / pixel 256 Color,3-3-2
 *              3:3-bit / pixel 8 Color
 *              4:Disable
 *              5:16-bit / pixel 65K Color
 *              6:18-bit / pixel 262K Color
 *              7:24-bit / pixel 16.7M Color
 *              byte[2:0]->IFPF：This command is used by SPI_PF_SEL=0 or MPU or MIPI command mode.
 *              0：Disable
 *              1:8-bit / pixel 256 Gray
 *              2:8-bit / pixel 256 Color,3-3-2
 *              3:3-bit / pixel 8 Color
 *              4:Disable
 *              5:16-bit / pixel 65K Color
 *              6:18-bit / pixel 262K Color
 *              7:24-bit / pixel 16.7M Color
 *  @retval     无
 */
void SH8601Z_Control_Interface_Pixel_Format(uint8_t byte)
{
    uint8_t buf[1] = {0};
    buf[0] = byte & 0xf7;
    qspi_1l_write_command_and_data(COLMOD, buf, 1);
}

/*
 *  @breif      SH8601Z从上次最后一次结束的点开始发送数据
 *  @note
 *  @param      buf：数据
 *              buf_len：数据长度
 *  @retval     无
 */
void SH8601Z_Memory_Write_Continue(uint8_t *buf,uint16_t buf_len)
{
    qspi_4l_write_command_and_data(RAMWRC,buf,buf_len);
}

/*
 *  @breif      SH8601Z设置撕裂效应扫描行数
 *  @note
 *  @param      te_scanline：撕裂效应扫描行数
 *              TEM=0 & TE_SCANLINE=0：撕裂效果输出线仅包含v信息。
 *              TEM=0 & TE_SCANLINE≠0：撕裂效果输出线由第n行信息组成
 *              TEM=1 & TE_SCANLINE≠0：撕裂效果输出线仅包含v信息。
 *  @retval     无
 */
void SH8601Z_Set_Tear_ScanLine(uint16_t te_scanline)
{
    uint8_t buf[2] = {0};
    buf[0] = BYTE1(te_scanline);
    buf[1] = BYTE0(te_scanline);
    qspi_1l_write_command_and_data(WR_TESCAN, buf, 2);
}

/*
 *  @breif      SH8601Z读撕裂效应扫描行数
 *  @note       未实现
 *  @param      无
 *  @retval
 */
uint16_t SH8601Z_Read_Scan_Line_Number(void)
{
    return 0xffff;
}

/*
 *  @breif      SH8601Z关闭SPI读取
 *  @note       无
 *  @param      无
 *  @retval     无
 */
void SH8601Z_SPI_Read_Off(void)
{
    qspi_1l_write_command_and_data(SPI_RD_OFF, NULL, 0);
}

/*
 *  @breif      SH8601Z打开SPI读取
 *  @note       无
 *  @param      无
 *  @retval     无
 */
void SH8601Z_SPI_Read_On(void)
{
    qspi_1l_write_command_and_data(SPI_RD_ON, NULL, 0);
}

/*
 *  @breif      SH8601Z AOD模式关闭
 *  @note       无
 *  @param      无
 *  @retval     无
 */
void SH8601Z_AOD_Mode_Off(void)
{
    qspi_1l_write_command_and_data(AOD_OFF, NULL, 0);
}

/*
 *  @breif      SH8601Z AOD模式打开
 *  @note       无
 *  @param      无
 *  @retval     无
 */
void SH8601Z_AOD_Mode_On(void)
{
    qspi_1l_write_command_and_data(AOD_ON, NULL, 0);
}

/*
 *  @breif      SH8601Z 设置AOD模式的亮度
 *  @note       无
 *  @param      aod_dbv：AOD模式下的亮度
 *  @retval     无
 */
void SH8601Z_Write_Display_Brightness_Value_in_AOD_Mode(uint16_t aod_dbv)
{
    uint8_t buf[2] = {0};
    buf[0] = BYTE0(aod_dbv);
    buf[1] = BYTE1(aod_dbv) & 0x03;
    qspi_1l_write_command_and_data(AOD_WR_DISBV, buf, 2);
}

/*
 *  @breif      SH8601Z 读取AOD模式下的亮度
 *  @note       未实现
 *  @param      无
 *  @retval     无
 */
uint16_t SH8601Z_Read_Display_Brightness_Value_in_AOD_Mode(void)
{
    return 0xffff;
}

/*
 *  @breif      SH8601Z 设置深度休眠控制
 *  @note       无
 *  @param      dstb：
 *              0：深度休眠模式失能
 *              1：深度休眠模式使能
 *  @retval
 */
void SH8601Z_Deep_Standby_Control(uint8_t dstb)
{
    uint8_t buf[1] = {0};
    buf[0] = dstb & 0x01;
    qspi_1l_write_command_and_data(DSTB, buf, 1);
}

/*
 *  @breif      SH8601Z 设置正常模式下的亮度
 *  @note       无
 *  @param      dbv：正常模式下的亮度，范围（0-255）
 *  @retval     无
 */
void SH8601Z_Write_Display_Brightness_Value(uint16_t dbv)
{
    uint8_t buf[2] = {0};
    buf[0] = BYTE0(dbv);
    buf[1] = BYTE1(dbv) & 0x03;
    qspi_1l_write_command_and_data(WR_DISBV, buf, 2);
}

/*
 *  @breif      SH8601Z 读取正常模式下的亮度
 *  @note       未实现
 *  @param      无
 *  @retval
 */
uint16_t SH8601Z_Read_Display_Brightness_Value(void)
{
    return 0xffff;
}

/*
 *  @breif      SH8601Z 设置显示控制器1
 *  @note       无
 *  @param      byte[5]->BCTRL:亮度控制
 *              0：失能
 *              1：使能
 *              byte[3]->DISP_DM:显示调光
 *              0：关闭
 *              1：打开
 *  @retval
 */
void SH8601Z_Write_CTRL_Display_1(uint8_t byte)
{
    uint8_t buf[1] = {0};
    buf[0] = byte & 0x28;
    qspi_1l_write_command_and_data(WR_CTRLD1, buf, 1);
}

/*
 *  @breif      SH8601Z 读取显示控制器1
 *  @note       未实现
 *  @param      无
 *  @retval
 */
uint8_t SH8601Z_Read_CTRL_Display_1(void)
{
    return 0xff;
}

/*
 *  @breif      SH8601Z 设置显示控制器2
 *  @note       无
 *  @param      byte[1:0]->ACL_PROF：选择ACL配置文件
 *              0：ACL配置关闭
 *              1：选择ACL配置文件一
 *              2：选择ACL配置文件二
 *              3：选择ACL配置文件三
 *  @retval
 */
void SH8601Z_Write_CTRL_Display_2(uint8_t byte)
{
    uint8_t buf[1] = {0};
    buf[0] = byte & 0x03;
    qspi_1l_write_command_and_data(WR_CTRLD2, buf, 1);
}

/*
 *  @breif      SH8601Z 读取显示控制器2
 *  @note       未实现
 *  @param      无
 *  @retval
 */
uint8_t SH8601Z_Read_CTRL_Display_2(void)
{
    return 0xff;
}

/*
 *  @breif      SH8601Z 设置 日光可读性（Sunlight Readability Enhancement）
 *  @note       无
 *  @param      byte[2]->SRE_EN：SRE控制
 *              0：关闭
 *              1：打开
 *              byte[1:0]->SRE_MODE:SRE模式
 *              0：低
 *              1：低
 *              2：中
 *              3：高
 *  @retval
 */
void SH8601Z_Write_CE(uint8_t byte)
{
    uint8_t buf[1] = {0};
    buf[0] = byte & 0x07;
    qspi_1l_write_command_and_data(WR_CE, buf, 1);
}

/*
 *  @breif      SH8601Z 读取日光可读性设置
 *  @note       未实现
 *  @param      无
 *  @retval
 */
uint8_t SH8601Z_Read_CE(void)
{
    return 0xff;
}

/*
 *  @breif      SH8601Z 设置HBM模式下的亮度
 *  @note       无
 *  @param      hbm_dbv：HBM模式下的亮度
 *  @retval     无
 */
void SH8601Z_Write_Display_Brightness_Value_in_HBM_Mode(uint16_t hbm_dbv)
{
    uint8_t buf[2] = {0};
    buf[0] = BYTE0(hbm_dbv);
    buf[1] = BYTE1(hbm_dbv) & 0x03;
    qspi_1l_write_command_and_data(HBM_WR_DISBV, buf, 2);
}

/*
 *  @breif      SH8601Z 读取HBM模式下的亮度
 *  @note       未实现
 *  @param      无
 *  @retval
 */
uint16_t SH8601Z_Read_Display_Brightness_Value_in_HBM_Mode(void)
{
    return 0xff;
}

/*
 *  @breif      SH8601Z HBM模式控制
 *  @note       无
 *  @param      byte[5:4]->HBM_MODE：
 *              0： HBM 中的插值
 *              1： HBM 中的插值
 *              2： 立即改变HBM模式中的伽马值设置1
 *              3： 立即改变HBM模式中的伽马值设置2
 *              byte[1]->HBM_EN：
 *              0：失能
 *              1：使能
 *  @retval
 */
void SH8601Z_HBM_Control(uint8_t byte)
{
    uint8_t buf[1] = {0};
    buf[0] = byte & 0x32;
    qspi_1l_write_command_and_data(HBM_CTRL, buf, 1);
}

/*
 *  @breif      SH8601Z SPI像素格式设置
 *  @note       这个要看数据手册
 *  @param
 *  @retval
 */
void SH8601Z_Pixel_Format_Option(uint8_t byte)
{
    uint8_t buf[1] = {0};
    buf[0] = byte & 0x4f;
    qspi_1l_write_command_and_data(COLOPT, buf, 1);
}

/*
 *  @breif      SH8601Z 读取供应商标识并显示DDh的模块型号/版本信息。
 *  @note       未实现
 *  @param      无
 *  @retval
 */
void SH8601Z_Read_DDB_Start(uint8_t *ddb)
{

}

/*
 *  @breif      SH8601Z 读取读取供应商标识并显示DDh的模块型号/版本信息。
 *  @note       未实现
 *  @param      无
 *  @retval
 */
void SH8601Z_Read_DDB_Continue(uint8_t *ddbn)
{

}

/*
 *  @breif      SH8601Z 该命令返回在对这些寄存器进行写访问后从“用户命令集”区域寄存器(不包括“制造命令集”)计算出的第一个校验和。
 *  @note       未实现
 *  @param      无
 *  @retval
 */
uint8_t SH8601Z_Read_First_Checksum(void)
{
    return 0xff;
}

/*
 *  @breif      SH8601Z 该命令返回连续校验和，该校验和是在对“用户命令集”区域寄存器进行写访问后从这些寄存器中计算出第一个校验和后连续计算出来的。
 *  @note       未实现
 *  @param      无
 *  @retval
 */
uint8_t SH8601Z_Read_Continue_Checksum(void)
{
    return 0xff;
}

/*
 *  @breif      SH8601Z 设置SPI模式控制
 *  @note       无
 *  @param      byte[5:4]->DUAL_PMODE：RGB图像数据传输格式为SPI3、4W接口模式
 *              0：1P / 1T 1 line
 *              1：1P / 1T 2 line
 *              2：2P / 3T 1 line
 *              byte[1]->SDIO_MODE：在SPI3,4W接口模式下读取协议
 *              0：SDI
 *              1:SDI+SDO
 *              byte[0]->DUAL_EN：双模式在SPI3,4W接口模式下启用
 *              0：失能
 *              1：使能
 *  @retval     无
 */
void SH8601Z_SPI_Mode_Control(uint8_t byte)
{
    uint8_t buf[1] = {0};
    buf[0] = byte & 0x33;
    qspi_1l_write_command_and_data(SPI_MODE, buf, 1);
}

/*
 *  @breif      SH8601Z 读ID
 *  @note       未实现
 *  @param      无
 *  @retval
 */
uint32_t SH8601Z_Read_ID(void)
{
    return 0xffffffff;
}

/*
 *  @breif      SH8601Z 填充函数
 *  @note       该函数需要自己移植，现在这个作为阻塞发送的例子
 *  @param      xs：起始列
 *              ys：起始行
 *              xe：结束列
 *              ye：结束行
 *              color：颜色
 *  @retval     无
 */
void SH8601Z_Fill(uint16_t xs,uint16_t ys,uint16_t xe,uint16_t ye,uint16_t color)
{
    uint16_t x_len = xe - xs + 1;
    uint16_t y_len = ye - ys + 1;
    uint8_t *p_color = (uint8_t *)malloc(x_len * 2 * SH8601Z_SEND_LINES);

    if(p_color == NULL)
        return;

    for(uint16_t index = 0;index < x_len * SH8601Z_SEND_LINES;index++)
    {
        p_color[2 * index + 0] = BYTE1(color);
        p_color[2 * index + 1] = BYTE0(color);
    }

    SH8601Z_Column_Address_Set(xs,xe);

    SH8601Z_Page_Address_Set(ys,ye);

    for(uint16_t index = 0;index < y_len / SH8601Z_SEND_LINES;index++)
    {
        if(index == 0)
            SH8601Z_Memory_Write_Start(p_color,x_len * 2 * SH8601Z_SEND_LINES);
        else
            SH8601Z_Memory_Write_Continue(p_color,x_len * 2 * SH8601Z_SEND_LINES);
    }

    free(p_color);
}

/*
 *  @breif      SH8601Z 画一个点
 *  @note       需要自己移植
 *  @param      x：x坐标
 *              y：y坐标
 *              color：颜色
 *  @retval     为
 */
void SH8601Z_Point(uint16_t x,uint16_t y,uint16_t color)
{
    static uint16_t transfer_num = 0;
    static spi_transaction_ext_t trans[3];
    spi_transaction_t *rtrans;

    for(uint16_t index = 0;index < transfer_num;index++)
        ESP_ERROR_CHECK(spi_device_get_trans_result(spi_device_handle,&rtrans,portMAX_DELAY));
    transfer_num = 0;

    for(uint16_t index = 0;index < 3;index++)
        memset(&trans[index],0, sizeof(spi_transaction_ext_t));

    trans[0].command_bits = 8;
    trans[0].address_bits = 24;
    trans[0].dummy_bits = 0;
    trans[0].base.cmd = 0x02;
    trans[0].base.addr = 0x002a00;
    trans[0].base.length = 8 * 4;
    trans[0].base.tx_data[0] = BYTE1(x);
    trans[0].base.tx_data[1] = BYTE0(x);
    trans[0].base.tx_data[2] = BYTE1(x);
    trans[0].base.tx_data[3] = BYTE0(x);
    trans[0].base.flags = (SPI_TRANS_USE_TXDATA | SPI_TRANS_MULTILINE_CMD | SPI_TRANS_MULTILINE_ADDR);

    trans[1].command_bits = 8;
    trans[1].address_bits = 24;
    trans[1].dummy_bits = 0;
    trans[1].base.cmd = 0x02;
    trans[1].base.addr = 0x002b00;
    trans[1].base.length = 8 * 4;
    trans[1].base.tx_data[0] = BYTE1(y);
    trans[1].base.tx_data[1] = BYTE0(y);
    trans[1].base.tx_data[2] = BYTE1(y);
    trans[1].base.tx_data[3] = BYTE0(y);
    trans[1].base.flags = (SPI_TRANS_USE_TXDATA | SPI_TRANS_MULTILINE_CMD | SPI_TRANS_MULTILINE_ADDR);

    trans[2].command_bits = 8;
    trans[2].address_bits = 24;
    trans[2].dummy_bits = 0;
    trans[2].base.cmd = 0x12;
    trans[2].base.addr = 0x002c00;
    trans[2].base.length = 8 * 2;
    trans[2].base.tx_data[0] = BYTE1(color);
    trans[2].base.tx_data[1] = BYTE0(color);
    trans[2].base.flags = (SPI_TRANS_MODE_QIO | SPI_TRANS_USE_TXDATA | SPI_TRANS_MULTILINE_ADDR);

    for(uint16_t index = 0;index < 3;index++)
    {
        ESP_ERROR_CHECK(spi_device_queue_trans(spi_device_handle,&trans[index].base,portMAX_DELAY));
        transfer_num ++;
    }
}

void SH8601Z_Flush_Old(uint16_t xs, uint16_t ys, uint16_t xe, uint16_t ye, void *p_color)
{
    uint16_t x_len = (xe - xs + 1) * 2;                             //本次发送列数 * 2 = 一列要发送的字节数
    uint16_t y_len = (ye - ys + 1);                                 //本次发送行数

    uint32_t chunk_lines = SH8601Z_SEND_MAX_SIZE / x_len;           //一次最大发行数 = 缓冲区 除以 一列要发送的字节数
    uint32_t size_per_chunk = chunk_lines * x_len;                  //一次发送的字节数 = 一次最大发行数 * 一列要发送的字节数
    uint32_t chunk_num = y_len / chunk_lines;                       //最大发送行数 = 本次发送行数 除以 一次最大发行数
    uint32_t remain_lines = y_len % chunk_lines;                    //剩余行数 = 本次发送行数 求余 一次最大发行数
    uint32_t chunk_total = chunk_num + (remain_lines > 0 ? 1 : 0);  //总发送行数 = 最大发送行数 加上 有剩余行数 > 0 ? 1 : 0
    uint32_t data_offset = 0;                                       //指针偏移
    uint32_t data_times = 0;                                        //发数据的次数

    uint8_t *color_map_ptr = (uint8_t *)p_color;                    //创建一个指针指向传进来的数组

    spi_transaction_ext_t tran[16];                                 //使用队列发送实体，为什么是16？2个作为x和y的地址发送，368 * 448 * 2（屏幕总字节） / 368 * 2 * 32（一次发送最大字节） = 14
    static uint32_t transfer_num = 0;                               //使用队列发送总个数
    spi_transaction_t *rtrans;                                      //检查 使用队列发送完成 的变量

    /*
     *  进来首先先等待上次发送完毕
     *  transfer_num 要记得清零
     */
    for(uint32_t index = 0;index < transfer_num;index++)
        ESP_ERROR_CHECK(spi_device_get_trans_result(spi_device_handle,&rtrans,portMAX_DELAY));
    transfer_num = 0;

    /*
     *   初始化发送结构体
     */
    for(uint16_t index = 0;index < 16;index++)
        memset(&tran[index],0, sizeof(spi_transaction_ext_t));

    /*
     *  设置发送x起始和x结束的命令
     */
    tran[0].command_bits = 8;
    tran[0].address_bits = 24;
    tran[0].dummy_bits = 0;
    tran[0].base.cmd = 0x02;
    tran[0].base.addr = 0x002a00;
    tran[0].base.tx_data[0] = BYTE1(xs);
    tran[0].base.tx_data[1] = BYTE0(xs);
    tran[0].base.tx_data[2] = BYTE1(xe);
    tran[0].base.tx_data[3] = BYTE0(xe);
    tran[0].base.length = 8 * 4;
    tran[0].base.flags = (SPI_TRANS_USE_TXDATA | SPI_TRANS_MULTILINE_CMD | SPI_TRANS_MULTILINE_ADDR);

    /*
     *  设置发送y起始和y结束的命令
     */
    tran[1].command_bits = 8;
    tran[1].address_bits = 24;
    tran[1].dummy_bits = 0;
    tran[1].base.cmd = 0x02;
    tran[1].base.addr = 0x002b00;
    tran[1].base.tx_data[0] = BYTE1(ys);
    tran[1].base.tx_data[1] = BYTE0(ys);
    tran[1].base.tx_data[2] = BYTE1(ye);
    tran[1].base.tx_data[3] = BYTE0(ye);
    tran[1].base.length = 8 * 4;
    tran[1].base.flags = (SPI_TRANS_USE_TXDATA | SPI_TRANS_MULTILINE_CMD | SPI_TRANS_MULTILINE_ADDR);

    /*
     *  开始发送数据字节
     *  注意第一次发送必须要发 0x002c00 ，之后的其他时刻为 0x003c00
     */
    for(uint32_t index = 0;index < chunk_total;index++)
    {
        if(index < chunk_num)
        {
            tran[2 + index].command_bits = 8;
            tran[2 + index].address_bits = 24;
            tran[2 + index].dummy_bits = 0;
            tran[2 + index].base.cmd = 0x12;
            if(index == 0)
                tran[2 + index].base.addr = 0x002c00;
            else
                tran[2 + index].base.addr = 0x003c00;
            tran[2 + index].base.length = 8 * size_per_chunk;
            tran[2 + index].base.tx_buffer = (void *)(color_map_ptr + data_offset);
            tran[2 + index].base.flags = (SPI_TRANS_MODE_QIO | SPI_TRANS_MULTILINE_ADDR);

            data_offset += size_per_chunk;
        }
        else
        {
            tran[2 + index].command_bits = 8;
            tran[2 + index].address_bits = 24;
            tran[2 + index].dummy_bits = 0;
            tran[2 + index].base.cmd = 0x12;
            tran[2 + index].base.addr = 0x003c00;
            tran[2 + index].base.length = 8 * remain_lines * x_len;
            tran[2 + index].base.tx_buffer = (void *)(color_map_ptr + data_offset);
            tran[2 + index].base.flags = (SPI_TRANS_MODE_QIO | SPI_TRANS_MULTILINE_ADDR);
        }
        data_times++;
    }
    /*
     *  使用队列发送 刷新区域的命令
     *  注意记得 transfer_num 要自加
     */
    for(uint32_t index = 0;index < 2 + data_times;index++)
    {
        ESP_ERROR_CHECK(spi_device_queue_trans(spi_device_handle,&tran[index].base,portMAX_DELAY));
        transfer_num++;
    }
}

/*
 *  @breif      SH8601Z清屏操作
 *  @note       阻塞发送，切而且使用的是heap中的数组
 *  @param      color：颜色
 *  @retval     无
 */
void SH8601Z_Clear(uint16_t color)
{
    uint16_t xs = 0,ys = 0,xe = SH8601Z_WIDTH,ye = SH8601Z_HIGHT;
    uint16_t x_len = (xe - xs + 1) * 2 * 32;
    uint16_t y_len = (ye - ys + 1) / 32;
    uint8_t *p = NULL;

    spi_transaction_ext_t trans[16] = {0};

    for(uint8_t index = 0;index < 16;index++)
        memset(&trans[index],0, sizeof(spi_transaction_ext_t));

    p = (uint8_t *) heap_caps_malloc(x_len,MALLOC_CAP_DMA);
    if(p == NULL)
    {
        ESP_LOGW("sh8601z","heap malloc failure!\r\n");
        return;
    }
    else
        ESP_LOGW("sh8601z","heap malloc success!\r\n");

    for(uint32_t index = 0;index < x_len / 2;index++)
    {
        p[2 * index + 0] = BYTE1(color);
        p[2 * index + 1] = BYTE0(color);
    }

    trans[0].command_bits = 8;
    trans[0].address_bits = 24;
    trans[0].dummy_bits = 0;
    trans[0].base.cmd = 0x02;
    trans[0].base.addr = 0x002a00;
    trans[0].base.length = 8 * 4;
    trans[0].base.user = (void *)0;
    trans[0].base.tx_data[0] = BYTE1(xs);
    trans[0].base.tx_data[1] = BYTE0(xs);
    trans[0].base.tx_data[2] = BYTE1(xe);
    trans[0].base.tx_data[3] = BYTE0(xe);
    trans[0].base.flags = (SPI_TRANS_USE_TXDATA | SPI_TRANS_MULTILINE_CMD | SPI_TRANS_MULTILINE_ADDR);

    trans[1].command_bits = 8;
    trans[1].address_bits = 24;
    trans[1].dummy_bits = 0;
    trans[1].base.cmd = 0x02;
    trans[1].base.addr = 0x002b00;
    trans[1].base.length = 8 * 4;
    trans[1].base.user = (void *)0;
    trans[1].base.tx_data[0] = BYTE1(ys);
    trans[1].base.tx_data[1] = BYTE0(ys);
    trans[1].base.tx_data[2] = BYTE1(ye);
    trans[1].base.tx_data[3] = BYTE0(ye);
    trans[1].base.flags = (SPI_TRANS_USE_TXDATA | SPI_TRANS_MULTILINE_CMD | SPI_TRANS_MULTILINE_ADDR);

    for(uint16_t index = 2;index < y_len + 2;index++)
    {
        trans[index].command_bits = 8;
        trans[index].address_bits = 24;
        trans[index].dummy_bits = 0;
        trans[index].base.cmd = 0x12;
        trans[index].base.addr = ((index == 2) ? 0x002c00 : 0x003c00);
        trans[index].base.length = 8 * x_len;
        trans[index].base.user = (void *)1;
        trans[index].base.tx_buffer = (uint8_t *)p;
        trans[index].base.flags = (SPI_TRANS_MODE_QIO | SPI_TRANS_MULTILINE_ADDR);
    }

    /*
     *  阻塞发送
     */
    for(uint16_t index = 0;index < 16;index++)
        ESP_ERROR_CHECK(spi_device_polling_transmit(spi_device_handle,&trans[index].base));

    heap_caps_free(p);
    ESP_LOGW("sh8601z","heap free success!\r\n");
}

void SH8601Z_Flush(uint16_t xs,uint16_t ys,uint16_t xe,uint16_t ye,void *p)
{
    uint16_t x_len = (xe - xs + 1);
    uint16_t y_len = (ye - ys + 1);
    uint32_t line_len = x_len * 2;

    static spi_transaction_ext_t trans[3];
    spi_transaction_t *rtran;
    static uint16_t transfer_total_times = 0;

    for(uint16_t index = 0;index < transfer_total_times;index++)
        ESP_ERROR_CHECK(spi_device_get_trans_result(spi_device_handle,&rtran,portMAX_DELAY));

    transfer_total_times = 0;

    for(uint16_t index = 0;index < 3;index++)
        memset(&trans[index],0, sizeof(spi_transaction_ext_t));

    trans[0].command_bits = 8;
    trans[0].address_bits = 24;
    trans[0].dummy_bits = 0;
    trans[0].base.cmd = 0x02;
    trans[0].base.addr = 0x002a00;
    trans[0].base.user = (void *)100;
    trans[0].base.length = 8 * 4;
    trans[0].base.tx_data[0] = BYTE1(xs);
    trans[0].base.tx_data[1] = BYTE0(xs);
    trans[0].base.tx_data[2] = BYTE1(xe);
    trans[0].base.tx_data[3] = BYTE0(xe);
    trans[0].base.flags = (SPI_TRANS_USE_TXDATA | SPI_TRANS_MULTILINE_CMD | SPI_TRANS_MULTILINE_ADDR);

    trans[1].command_bits = 8;
    trans[1].address_bits = 24;
    trans[1].dummy_bits = 0;
    trans[1].base.cmd = 0x02;
    trans[1].base.addr = 0x002b00;
    trans[1].base.user = (void *)100;
    trans[1].base.length = 8 * 4;
    trans[1].base.tx_data[0] = BYTE1(ys);
    trans[1].base.tx_data[1] = BYTE0(ys);
    trans[1].base.tx_data[2] = BYTE1(ye);
    trans[1].base.tx_data[3] = BYTE0(ye);
    trans[1].base.flags = (SPI_TRANS_USE_TXDATA | SPI_TRANS_MULTILINE_CMD | SPI_TRANS_MULTILINE_ADDR);

    trans[2].command_bits = 8;
    trans[2].address_bits = 24;
    trans[2].dummy_bits = 0;
    trans[2].base.cmd = 0x12;
    trans[2].base.addr = 0x002c00;
    trans[2].base.user = (void *)101;
    trans[2].base.length = 8 * line_len * y_len;
    trans[2].base.tx_buffer = p;
    trans[2].base.flags = (SPI_TRANS_MODE_QIO | SPI_TRANS_MULTILINE_ADDR);

    for(uint16_t index = 0;index < 3;index++)
    {
        ESP_ERROR_CHECK(spi_device_queue_trans(spi_device_handle,&trans[index].base,portMAX_DELAY));
        transfer_total_times++;
    }
}
